package cn.edu.usst.cs.gjy;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import static cn.edu.usst.cs.pi2.KMP.getInts;

public class PiSearch {
    // 要查找的数字
    private static final String N = "6939937510";
    // 要查找第99次出现的位置
    private static final int TARGET_OCCURRENCE = 99;
    // 使用的线程数量，可以根据CPU核心数调整
    private static final int NUM_THREADS = 8;
    // 文件路径
    public static final String PI_FILE_PATH = "E:\\pi_dec_1t_01\\pi_dec_1t_01.txt";

    // 用于记录当前找到的次数，使用AtomicInteger以保证线程安全
    private static AtomicInteger occurrenceCount = new AtomicInteger(0);
    // 记录第99次出现的位置，初始值为-1表示未找到
    private static AtomicLong position = new AtomicLong(-1);
    // 用于停止所有线程的标志
    private static AtomicBoolean stopSearch = new AtomicBoolean(false);

    public static void main(String[] args) {
        // 创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);
        // 每个线程处理的文件内容大小
        int chunkSize = 1000000; // 适当调整每个线程处理的块大小
        int overlap = N.length() - 1;

        try (FileInputStream fis = new FileInputStream(PI_FILE_PATH)) {
            ByteBuffer buffer = ByteBuffer.allocate(chunkSize + overlap);
            long totalPosition = 0;
            int bytesRead;

            while ((bytesRead = fis.read(buffer.array())) != -1) {
                int currentEnd = bytesRead;
                if (currentEnd > chunkSize) {
                    currentEnd = chunkSize;
                }
                long end = totalPosition + currentEnd;
                CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer);
                String partialPi = charBuffer.toString().substring(0, currentEnd);
                executorService.execute(new SearchTask(partialPi, totalPosition, end));
                totalPosition = end - overlap; // 重叠处理，确保不会错过跨越块的匹配
                buffer.clear(); // 清空缓冲区，以准备下一次读取
            }

            // 处理剩余的部分
            if (position.get() == -1) {
                CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer);
                String remainingPi = charBuffer.toString().trim(); // 确保没有多余的空白字符
                if (remainingPi.length() > 0) {
                    executorService.execute(new SearchTask(remainingPi, totalPosition, totalPosition + remainingPi.length()));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 关闭线程池，不再接受新任务
        executorService.shutdown();
        try {
            // 等待所有线程执行完毕
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 输出结果
        if (position.get() != -1) {
            System.out.println("数字 " + N + " 在π中第99次出现的位置是从第 " + position.get() + " 位开始");
        } else {
            System.out.println("在搜索范围内未找到数字 " + N + " 的第99次出现位置。");
        }
    }

    // 搜索任务类，每个线程执行一段范围的搜索
    static class SearchTask implements Runnable {
        private final String piDigits;
        private final long start;
        private final long end;

        SearchTask(String piDigits, long start, long end) {
            this.piDigits = piDigits;
            this.start = start;
            this.end = end;
        }

        @Override
        public void run() {
            int len = N.length();
            int i = 0, j = 0;
            int[] lps = computeLPSArray(N);

            while (i < piDigits.length() && !stopSearch.get()) {
                if (piDigits.charAt(i) == N.charAt(j)) {
                    i++;
                    j++;
                } else {
                    if (j != 0) {
                        j = lps[j - 1];
                    } else {
                        i++;
                    }
                }

                if (j == len) {
                    // 找到数字N，增加计数
                    int currentCount = occurrenceCount.incrementAndGet();
                    // 计算实际位置
                    long actualPosition = start + i - len;

                    // 输出找到的次数
                    System.out.println("找到数字 " + N + " 的第 " + currentCount + " 次出现位置是从第 " + actualPosition + " 位开始");

                    // 如果找到了第99次出现的位置，记录并停止搜索
                    if (currentCount == TARGET_OCCURRENCE) {
                        position.set(actualPosition);
                        stopSearch.set(true);
                        break;
                    }

                    j = lps[j - 1];
                }
            }
        }

        // 计算KMP算法的LPS数组
        private int[] computeLPSArray(String pattern) {
            return getInts(pattern);
        }
    }
}